package qc.module.qms.service;

import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QmsCacheConstant;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.common.core.utils.IdentifierUtil;
import qc.module.qms.dto.station.StationCategoryRelationDto;
import qc.module.qms.dto.station.StationCategoryRelationSetDto;
import qc.module.qms.entity.QmsStation;
import qc.module.qms.entity.QmsStationCategory;
import qc.module.qms.entity.QmsStationCategoryRelation;
import qc.module.qms.mapper.QmsStationCategoryRelationMapper;
import qc.module.qms.repository.QmsStationCategoryRelationRepository;
import qc.module.qms.repository.QmsStationCategoryRepository;
import qc.module.qms.mapper.QmsStationCategoryMapper;
import qc.module.qms.dto.station.StationCategoryDto;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 站点分类Service
 * 负责管理站点分类信息及其与站点的关联关系
 *
 * @author QuCheng Tech
 * @since 2025/10/25
 */
@Service
public class QmsStationCategoryService {

    private static final Logger logger = LoggerFactory.getLogger(QmsStationCategoryService.class);

    private static final String CACHE_KEY_STATION_CATEGORY = QmsCacheConstant.CACHE_KEY_STATION_CATEGORY_ENTITY;

    @Autowired
    private QmsStationCategoryRepository repository;
    
    @Autowired
    private QmsStationCategoryRelationRepository relationRepository;
    
    @Autowired
    private QmsStationService stationService;

    /**
     * 更新缓存，不管是否有缓存数据都进行更新
     * 用于在数据变更后主动刷新缓存
     *
     * @return java.util.List<qc.module.qms.dto.station.StationCategoryDto>
     * @author QuCheng Tech
     * @since 2025/10/25
     */
    @CachePut(value = CACHE_KEY_STATION_CATEGORY)
    public List<StationCategoryDto> cachePut() {
        logger.debug("cachePut");

        return getAllCategoryFromDb();
    }

    /**
     * 清除缓存
     * 用于在数据变更前清除旧缓存数据
     *
     * @author QuCheng Tech
     * @since 2025/10/25
     */
    @CacheEvict(value = CACHE_KEY_STATION_CATEGORY)
    public void cacheEvict() {
        logger.debug("cacheEvict");
    }

    /**
     * 获取全部站点分类信息；有缓存时从缓存获取，没有缓存时从数据库中获取并放入缓存
     * 提供高性能的分类信息查询接口
     *
     * @return java.util.List<qc.module.qms.dto.station.StationCategoryDto>
     * @author QuCheng Tech
     * @since 2025/10/25
     */
    @Cacheable(value = CACHE_KEY_STATION_CATEGORY)
    public List<StationCategoryDto> getAllCategoryWithCache() {
        logger.debug("getAllWithCache");

        return getAllCategoryFromDb();
    }

    /**
     * 从数据库中获取全部站点分类信息
     * 按分类名称升序排列
     *
     * @return java.util.List<qc.module.qms.dto.station.StationCategoryDto>
     * @author QuCheng Tech
     * @since 2025/10/25
     */
    public List<StationCategoryDto> getAllCategoryFromDb() {
    logger.debug("getAllFromDb 从数据库中查询所有站点分类信息");
    
    LambdaQueryWrapper<QmsStationCategory> wrapper = new LambdaQueryWrapper<>();
    
    // 按分类名称升序排序
    wrapper.orderByAsc(QmsStationCategory::getCtgname);
    List<QmsStationCategory> entities = repository.selectList(wrapper);
    // 增加更全面的非空判断，包括null和empty情况
    if (entities == null || entities.isEmpty()) {
        return null;
    }
    List<StationCategoryDto> dtos = QmsStationCategoryMapper.MAPPER.toDtoList(entities);
    // 对转换后的结果也进行非空判断
    if (dtos == null || dtos.isEmpty()) {
        return null;
    }
    
    return dtos;
    }


    /**
     * 新增站点分类
     * 业务功能：创建一个新的站点分类，如"水位站"、"雨量站"等
     * 校验参数：
     * 1. 分类信息对象不能为空
     * 2. 分类编码不能为空
     * 3. 分类名称不能为空
     * 4. 分类编码不能重复
     * 5. 分类名称不能重复
     *
     * @param dto 站点分类信息DTO，包含分类编码(ctgcode)和分类名称(ctgname)
     * @return String 成功返回null，失败返回错误信息
     */
    public String addCategory(StationCategoryDto dto) {
        String result = null;
        
        if (dto == null) {
            result = QCUnifyReturnValue.Warn("站点分类信息不能为空，请检查输入参数");
        } else if (StringUtils.isBlank(dto.getCtgcode())) {
            result = QCUnifyReturnValue.Warn("分类编码不能为空，请输入分类编码");
        } else if (StringUtils.isBlank(dto.getCtgname())) {
            result = QCUnifyReturnValue.Warn("分类名称不能为空，请输入分类名称");
        } else if (isCategoryCodeExist(dto.getCtgcode(), null)) {
            result = QCUnifyReturnValue.Warn("分类编码[" + dto.getCtgcode() + "]已存在，请重新输入");
        } else if (isCategoryNameExist(dto.getCtgname(), dto.getCtgcode())) {
            result = QCUnifyReturnValue.Warn("分类名称[" + dto.getCtgname() + "]已存在，请重新输入");
        } else {
            QmsStationCategory en = QmsStationCategoryMapper.MAPPER.toEntity(dto);
            if (repository.insert(en) < 0x1) {
                result = QCUnifyReturnValue.Warn("新增站点分类[" + dto.getCtgname() + "]失败，请稍后重试");
            }
        }

        return result == null ? QCUnifyReturnValue.Success() : result;
    }

    /**
     * 修改站点分类信息
     * 业务功能：更新已存在的站点分类信息
     * 校验参数：
     * 1. 分类信息对象不能为空
     * 2. 分类编码不能为空
     * 3. 分类名称不能为空
     * 4. 要修改的分类必须存在
     * 5. 新的分类名称不能与其他分类重复（排除自身）
     *
     * @param dto 站点分类信息，包含分类编码(ctgcode)和分类名称(ctgname)
     * @return String 成功返回null，失败返回错误信息
     */
    public String updateCategory(StationCategoryDto dto) {
        String result = null;
        
        if (dto == null) {
            result = QCUnifyReturnValue.Warn("站点分类信息不能为空，请检查输入参数");
        } else if (StringUtils.isBlank(dto.getCtgcode())) {
            result = QCUnifyReturnValue.Warn("分类编码不能为空，请输入分类编码");
        } else if (StringUtils.isBlank(dto.getCtgname())) {
            result = QCUnifyReturnValue.Warn("分类名称不能为空，请输入分类名称");
        } else if (!isCategoryCodeExist(dto.getCtgcode(), dto.getCtgcode())) {
            result = QCUnifyReturnValue.Warn("要修改的站点分类[" + dto.getCtgcode() + "]不存在，请确认分类编码是否正确");
        } else if (isCategoryNameExist(dto.getCtgname(), dto.getCtgcode())) {
            result = QCUnifyReturnValue.Warn("分类名称[" + dto.getCtgname() + "]已存在，请重新输入");
        } else {
            QmsStationCategory en = QmsStationCategoryMapper.MAPPER.toEntity(dto);
            if (repository.updateById(en) < 0x1) {
                result = QCUnifyReturnValue.Warn("修改站点分类[" + dto.getCtgname() + "]失败，请稍后重试");
            }
        }

        return result == null ? QCUnifyReturnValue.Success() : result;
    }
    
    /**
     * 删除指定站点分类
     * 业务功能：删除站点分类，同时级联删除该分类下的所有站点关联关系
     * 校验参数：
     * 1. 分类编码不能为空
     *
     * @param ctgcode 分类编码，如"waterstation"(水位站)、"rainstation"(雨量站)等
     * @return String 删除成功返回null，删除失败返回错误信息
     */
    public String deleteCategory(String ctgcode) {
        String result = null;
        
        if (StringUtils.isBlank(ctgcode)) {
            result = QCUnifyReturnValue.Warn("分类编码不能为空，请输入分类编码");
        } else {
            // 先删除分类中的站点关联关系
            LambdaQueryWrapper<QmsStationCategoryRelation> relationWrapper = new LambdaQueryWrapper<>();
            relationWrapper.eq(QmsStationCategoryRelation::getCtgcode, ctgcode);
            relationRepository.delete(relationWrapper);
            
            // 再删除站点分类本身
            repository.deleteById(ctgcode);
        }

        return result == null ? QCUnifyReturnValue.Success() : result;
    }

    /**
     * 获取指定分类下的所有站点
     * 业务功能：查询某个分类下关联的所有站点，并按排序号升序排列
     * 校验参数：
     * 1. 分类编码不能为空
     *
     * @param ctgcode 分类编码，如"waterstation"(水位站)、"rainstation"(雨量站)等
     * @return List<StationCategoryRelationDto> 站点分类关联关系列表，包含站点编码、站点名称、排序号等信息
     */
    public List<StationCategoryRelationDto> getCategoryStations(String ctgcode) {
        List<StationCategoryRelationDto> result = null;

        if (StringUtils.isBlank(ctgcode)) {
            result = null;
        } else {
            // 查询指定分类下的所有站点关联关系，按排序号升序排列
            List<QmsStationCategoryRelation> relations = relationRepository.selectList(
                    new LambdaQueryWrapper<QmsStationCategoryRelation>()
                            .eq(QmsStationCategoryRelation::getCtgcode, ctgcode)
                            .orderByAsc(QmsStationCategoryRelation::getOdr)
            );
            
            if (relations != null && !relations.isEmpty()) {
                List<StationCategoryRelationDto> dtos = QmsStationCategoryRelationMapper.MAPPER.toDtoList(relations);
                if (dtos != null) {
                    // 一次获取全部站点集合信息，从缓存中获取数据，提高性能
                    List<QmsStation> allStations = stationService.getAllWithCache();
                    if (allStations != null) {
                        // 构建站点编码到站点实体的映射，提高查找效率
                        Map<String, QmsStation> stationMap = allStations.stream()
                                .collect(Collectors.toMap(QmsStation::getStcd, station -> station));
                        
                        // 为每个DTO设置站点名称，用于界面显示
                        for (StationCategoryRelationDto dto : dtos) {
                            QmsStation station = stationMap.get(dto.getStcd());
                            if (station != null) {
                                dto.setStnm(station.getStnm());
                            }
                        }
                    }
                    result = dtos;
                }
            }
        }

        return result;
    }
    
    /**
     * 设置站点分类下的站点
     * 业务功能：完全替换某个分类下的站点关联关系，先清空原有关系再添加新关系
     * 校验参数：
     * 1. 参数对象不能为空
     * 2. 分类编码不能为空
     * 3. 指定的分类必须存在
     *
     * @param dto 站点分类关联设置DTO，包含分类编码(ctgcode)和站点编码数组(stcds)
     * @return String 设置成功返回null，设置失败返回错误信息
     */
    public String setCategoryStations(StationCategoryRelationSetDto dto) {
        String result = null;

        if (dto == null) {
            result = QCUnifyReturnValue.Warn("站点分类关联设置参数不能为空，请检查输入参数");
        } else if (StringUtils.isBlank(dto.getCtgcode())) {
            result = QCUnifyReturnValue.Warn("分类编码不能为空，请输入分类编码");
        } else if (!isCategoryCodeExist(dto.getCtgcode(), null)) {
            result = QCUnifyReturnValue.Warn("指定的站点分类[" + dto.getCtgcode() + "]不存在，请确认分类编码是否正确");
        } else {
            // 先清空指定分类下的所有关联关系
            LambdaQueryWrapper<QmsStationCategoryRelation> deleteWrapper = new LambdaQueryWrapper<>();
            deleteWrapper.eq(QmsStationCategoryRelation::getCtgcode, dto.getCtgcode());
            relationRepository.delete(deleteWrapper);

            // 如果有新的站点编码，则逐个添加关联关系
            if (dto.getStcds() != null && dto.getStcds().length > 0) {
                for (int i = 0; i < dto.getStcds().length; i++) {
                    String stcd = dto.getStcds()[i];
                    
                    // 设置关联关系
                    QmsStationCategoryRelation relation = new QmsStationCategoryRelation();
                    relation.setId(IdentifierUtil.simpleUUID()); // 生成唯一ID
                    relation.setCtgcode(dto.getCtgcode()); // 设置分类编码
                    relation.setStcd(stcd); // 设置站点编码
                    relation.setOdr(i); // 按数组顺序设置排序号
                    
                    // 插入关联关系
                    if (relationRepository.insert(relation) < 1) {
                        result = QCUnifyReturnValue.Warn("设置站点分类关联关系失败，请稍后重试");
                        break;
                    }
                }
            }
        }

        return result == null ? QCUnifyReturnValue.Success() : result;
    }

    /**
     * 新增分类中关联的站点
     * 业务功能：向某个分类中添加新的站点关联关系，不重复添加已存在的关系
     * 校验参数：
     * 1. 参数对象不能为空
     * 2. 分类编码不能为空
     * 3. 指定的分类必须存在
     *
     * @param dto 站点分类关联设置DTO，包含分类编码(ctgcode)和站点编码数组(stcds)
     * @return String 新增成功返回null，新增失败返回错误信息
     */
    public String addCategoryStations(StationCategoryRelationSetDto dto) {
        String result = null;

        if (dto == null) {
            result = QCUnifyReturnValue.Warn("站点分类关联设置参数不能为空，请检查输入参数");
        } else if (StringUtils.isBlank(dto.getCtgcode())) {
            result = QCUnifyReturnValue.Warn("分类编码不能为空，请输入分类编码");
        } else if (!isCategoryCodeExist(dto.getCtgcode(), null)) {
            result = QCUnifyReturnValue.Warn("指定的站点分类[" + dto.getCtgcode() + "]不存在，请确认分类编码是否正确");
        } else if (dto.getStcds() != null && dto.getStcds().length > 0) {
            // 查询当前分类下已有的关联关系，避免重复添加
            LambdaQueryWrapper<QmsStationCategoryRelation> existWrapper = new LambdaQueryWrapper<>();
            existWrapper.eq(QmsStationCategoryRelation::getCtgcode, dto.getCtgcode());
            List<QmsStationCategoryRelation> existingRelations = relationRepository.selectList(existWrapper);

            // 获取已存在的站点编码集合，用于快速查找
            List<String> existingStations = new ArrayList<>();
            if (existingRelations != null && !existingRelations.isEmpty()) {
                for (QmsStationCategoryRelation relation : existingRelations) {
                    existingStations.add(relation.getStcd());
                }
            }

            // 获取当前最大排序号，新添加的站点在此基础上递增
            Integer maxOrder = null;
            if (existingRelations != null && !existingRelations.isEmpty()) {
                maxOrder = existingRelations.stream()
                        .mapToInt(QmsStationCategoryRelation::getOdr)
                        .max()
                        .orElse(0);
            } else {
                maxOrder = -1; // 如果没有现有记录，则从0开始
            }

            // 遍历新的站点编码数组，逐个添加关联关系
            for (String stcd : dto.getStcds()) {
                // 如果已存在关联关系则跳过
                if (existingStations.contains(stcd)) {
                    continue;
                }
                
                // 设置关联关系
                QmsStationCategoryRelation relation = new QmsStationCategoryRelation();
                relation.setId(IdentifierUtil.simpleUUID()); // 生成唯一ID
                relation.setCtgcode(dto.getCtgcode()); // 设置分类编码
                relation.setStcd(stcd); // 设置站点编码
                relation.setOdr(++maxOrder); // 在最大排序号基础上递增
                
                // 插入关联关系
                if (relationRepository.insert(relation) < 1) {
                    result = QCUnifyReturnValue.Warn("添加站点分类关联关系失败，请稍后重试");
                    break;
                }
            }
        }
        
        return result == null ? QCUnifyReturnValue.Success() : result;
    }
    
    /**
     * 删除分类与站点的关联关系
     * 业务功能：根据关联关系ID删除指定的分类与站点关联关系
     * 校验参数：
     * 1. 关联关系ID集合不能为空
     *
     * @param ids 关联关系ID集合，每个ID对应一条分类与站点的关联记录
     * @return String 删除成功返回null，删除失败返回错误信息
     */
    public String deleteCategoryStations(List<String> ids) {
        String result = null;

        if (ids == null || ids.isEmpty()) {
            result = QCUnifyReturnValue.Warn("分类与站点关联关系ID集合不能为空，请输入关联关系ID");
        } else {
            // 遍历ID集合，逐个删除关联关系
            for (String id : ids) {
                if (StringUtils.isNotBlank(id)) {
                    relationRepository.deleteById(id.trim());
                }
            }
        }
        
        return result == null ? QCUnifyReturnValue.Success() : result;
    }

    /**
     * 设置分类与站点关联的排序号
     * 业务功能：修改指定关联关系的排序号，用于控制站点在分类中的显示顺序
     * 校验参数：
     * 1. 参数对象不能为空
     * 2. 关联关系ID不能为空
     * 3. 排序号必须为非负整数
     * 4. 指定的关联关系必须存在
     *
     * @param dto 分类与站点关联关系DTO，包含关联关系ID(id)和排序号(odr)
     * @return String 设置成功返回null，设置失败返回错误信息
     */
    public String setCategoryStationOrder(StationCategoryRelationDto dto) {
        String result = null;
        
        if (dto == null) {
            result = QCUnifyReturnValue.Warn("分类与站点关联关系参数不能为空，请检查输入参数");
        } else if (StringUtils.isBlank(dto.getId())) {
            result = QCUnifyReturnValue.Warn("关联关系ID不能为空，请输入关联关系ID");
        } else if (dto.getOdr() < 0) {
            result = QCUnifyReturnValue.Warn("排序号必须为正整数，请输入正确的排序号");
        } else {
            // 查询指定的关联关系
            QmsStationCategoryRelation relation = relationRepository.selectById(dto.getId());
            if (relation == null) {
                result = QCUnifyReturnValue.Warn("指定的关联关系不存在，请确认关联关系ID是否正确");
            } else {
                // 更新排序号
                relation.setOdr(dto.getOdr());
                if (relationRepository.updateById(relation) < 1) {
                    result = QCUnifyReturnValue.Warn("更新排序号失败，请稍后重试");
                }
            }
        }

        return result == null ? QCUnifyReturnValue.Success() : result;
    }

    /**
     * 检查指定分类编码是否存在
     * 业务功能：判断指定的分类编码是否已存在
     * 校验参数：
     * 1. 分类编码不能为空
     *
     * @param ctgcode 分类编码
     * @param excludeCtgcode 排除的分类编码（用于更新时排除自身）
     * @return boolean true表示存在，false表示不存在
     */
    private boolean isCategoryCodeExist(String ctgcode, String excludeCtgcode) {
        if (StringUtils.isBlank(ctgcode)) {
            return false;
        }
        LambdaQueryWrapper<QmsStationCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(QmsStationCategory::getCtgcode);
        wrapper.eq(QmsStationCategory::getCtgcode, ctgcode);
        
        if (StringUtils.isNotBlank(excludeCtgcode)) {
            wrapper.ne(QmsStationCategory::getCtgcode, excludeCtgcode);
        }
        return repository.selectCount(wrapper) > 0;
    }

    /**
     * 检查指定分类名称是否存在
     * 业务功能：判断指定的分类名称是否已存在
     * 校验参数：
     * 1. 分类名称不能为空
     *
     * @param ctgname 分类名称
     * @param excludeCtgname 排除的分类编码（用于更新时排除自身）
     * @return boolean true表示存在，false表示不存在
     */
    private boolean isCategoryNameExist(String ctgname, String excludeCtgname) {
        if (StringUtils.isBlank(ctgname)) {
            return false;
        }
        LambdaQueryWrapper<QmsStationCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(QmsStationCategory::getCtgcode);
        wrapper.eq(QmsStationCategory::getCtgname, ctgname);
        if (StringUtils.isNotBlank(excludeCtgname))
            wrapper.ne(QmsStationCategory::getCtgcode, excludeCtgname);
        return repository.selectCount(wrapper) > 0;
    }
    
}
